1 Présentation du projet

Dans le cadre de la formation DSA, nous avons eu l’occasion d’analyser un jeu de données de tarification MRH à l’occasion d’un Hackathon.

Du fait des ontraintes propres au Hackathon je n’avais pas eu l’occasion de finaliser l’analyse de ce jeu de données. Par ailleurs, pour le hackathon, le choix s’était porté sur le logiciel Python.

Ce TD est donc l’occasion de poursuivre l’analyse de ce jeu de données et d’explorer l’usage de packages et d’approches développés par MV Wütrich et disponible sur le site de l’association suisse des actuaires.

2 Analyse

2.1 Mise en place de l’environnement

Le code suivant est un ensemble d’utilitaire pour naviguer dans les répertoires relatifs du projet et installer ou charger les packages nécessaires à l’analyse :

if (!require("here")){ 
  install.packages("here") 
  library("here")
}

set_here

LoadPackage <- function (load.lib=c("")) {

  install.lib<-load.lib[!load.lib %in% installed.packages()]
  for(lib in install.lib) install.packages(lib,dependencies=TRUE)
  sapply(load.lib,require,character=TRUE)
  
}


LoadPackage(c('ggplot2', 'dplyr', 'formattable', 'DT', 'tidyr', 'caret', 'plotly'))

3 Présentation du jeu de données

Le jeu de données est constitué de 4 fichiers :

list.files(path=here('data', 'raw'))
## [1] "Data"                  "Data.zip"              "dsa2021_hackathon.zip"
## [4] "expo_test.csv"         "expo_train.csv"        "primes2019.csv"       
## [7] "sin_train.csv"

Le projet suit un portefeuille d’assurance MRH suivi sur plusieurs années de 2016 à 2018 inclus. L’objectif initial du Hackathon est d’estimer les primes 2019 sur un échantillon de contrats.

3.1 expo_train

Le fichier expo_train.csv contient la liste des contrats en risques historiquement suivis :

expo_train = read.table(file = here('data', 'raw', 'expo_train.csv'), header=T, sep=',', dec='.', encoding = 'UTF-8', stringsAsFactors = F)

datatable(head(expo_train))
str(expo_train)
## 'data.frame':    155651 obs. of  19 variables:
##  $ X                  : int  384538 441079 119668 5124 130065 450830 151401 296526 71801 360445 ...
##  $ EXPO               : num  1 0.825 1 1 1 ...
##  $ FORMULE            : chr  "MEDIUM" "CONFORT" "ESSENTIEL" "ESSENTIEL" ...
##  $ TYPE_RESIDENCE     : chr  "PRINCIPALE" "PRINCIPALE" "PRINCIPALE" "SECONDAIRE" ...
##  $ TYPE_HABITATION    : chr  "APPARTEMENT" "MAISON" "APPARTEMENT" "MAISON" ...
##  $ NB_PIECES          : int  1 NA 3 2 1 2 2 2 1 3 ...
##  $ SITUATION_JURIDIQUE: chr  "PROPRIO" "PROPRIO" "LOCATAIRE" "LOCATAIRE" ...
##  $ NIVEAU_JURIDIQUE   : chr  "JUR1" "JUR1" "JUR1" "JUR1" ...
##  $ VALEUR_DES_BIENS   : num  3500 0 35000 9000 20000 9000 20000 9000 3500 0 ...
##  $ OBJETS_DE_VALEUR   : chr  "NIVEAU_1" "NIVEAU_1" "NIVEAU_1" "NIVEAU_1" ...
##  $ ZONIER             : chr  "B40" "A11" "B32" "C24" ...
##  $ NBSIN_TYPE1_AN1    : int  0 0 0 0 0 0 1 0 0 0 ...
##  $ NBSIN_TYPE1_AN2    : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ NBSIN_TYPE1_AN3    : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ NBSIN_TYPE2_AN1    : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ NBSIN_TYPE2_AN2    : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ NBSIN_TYPE2_AN3    : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ id                 : int  5 9 11 13 14 15 20 21 28 30 ...
##  $ ANNEE              : int  2017 2018 2017 2018 2017 2017 2018 2016 2018 2016 ...

Les données ont été prétraitées pour disposer d’une ligne par période de risque annuelle homogène.

Pour des raisons d’anonymisation, les identifiants contrats ont été supprimés de sorte qu’il n’est pas possible de suivre l’évolution du risque d’une période sur l’autre. Pour la même raison, il ne sera pas possible dans la construction des jeux de validation et de test de s’assurer que toute l’expérience d’un même assuré est bien intégralement dans un jeu d’entraînement, de validation ou de test.

La signification des colonnes présentes est la suivante :

  • X: variable non nommée. Il s’agit d’un artefact du processus de création du fichier initial. On ne la prend pas en compte

  • EXPO : exposition en année risque du contrat. Sa valeur précalculée pour chaque ligne est comprise entre 0 et 1

##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
## 0.002732 0.811475 1.000000 0.837278 1.000000 1.000000

  • FORMULE : variable catégorielle codant la formule du contrat comprenant 3 niveaux MEDIUM, ESSENTIEL et CONFORT
FORMULE nb_lignes EXPO pct_EXPO
ALL_INCLUDE 6,671.00 4,759.51 3.65%
CONFORT 87,603.00 73,930.57 56.73%
ESSENTIEL 22,364.00 19,546.44 15.00%
MEDIUM 39,013.00 32,086.59 24.62%

  • TYPE_RESIDENCE : variable catégorielle codant le fait que le bien est une résidence PRINCIPALE, ou SECONDAIRE
TYPE_RESIDENCE nb_lignes EXPO pct_EXPO
PRINCIPALE 130,727.00 112,793.55 86.55%
SECONDAIRE 24,924.00 17,529.57 13.45%

  • TYPE_HABITATION : variable catégorielle codant le fait que le bien est un APPARTEMENT, ou une MAISON
TYPE_HABITATION nb_lignes EXPO pct_EXPO
APPARTEMENT 71,123.00 61,562.82 47.24%
MAISON 84,528.00 68,760.30 52.76%

  • NB_PIECES : variable numérique indiquant le nombre de pièces du logement
NB_PIECES nb_lignes EXPO pct_EXPO
0 3,718.00 2,413.72 1.85%
1 40,300.00 31,943.51 24.51%
2 60,973.00 51,931.99 39.85%
3 31,695.00 27,730.87 21.28%
4 9,615.00 8,495.12 6.52%
NA 9,350.00 7,807.90 5.99%

  • SITUATION_JURIDIQUE : variable catégorielle indiquant si le souscripteur est prorpiétaire (PROPRIO) ou locataire (LOCATAIRE) du logement assuré
SITUATION_JURIDIQUE nb_lignes EXPO pct_EXPO
LOCATAIRE 86,421.00 76,135.03 58.42%
PROPRIO 69,230.00 54,188.09 41.58%

  • NIVEAU_JURIDIQUE : variable catégorielle codant le niveau de couverture de la garantie juridique
NIVEAU_JURIDIQUE nb_lignes EXPO pct_EXPO
JUR1 153,568.00 128,854.03 98.87%
JUR2 2,083.00 1,469.09 1.13%

  • VALEUR_DES_BIENS : variable numérique reflétant la valeur couverte du contenu du logement
VALEUR_DES_BIENS nb_lignes EXPO pct_EXPO
0 8,307.00 5,259.05 4.04%
3500 51,879.00 40,929.10 31.41%
9000 34,770.00 30,059.53 23.07%
20000 33,745.00 29,664.65 22.76%
35000 11,528.00 10,299.00 7.90%
50000 7,944.00 7,243.56 5.56%
80000 6,534.00 6,018.46 4.62%
100000 944.00 849.77 0.65%

  • OBJETS_DE_VALEUR : variable catégorielle codant le niveau de couverture des objets
OBJETS_DE_VALEUR nb_lignes EXPO pct_EXPO
NIVEAU_1 145,959.00 121,738.34 93.41%
NIVEAU_2 9,692.00 8,584.78 6.59%

  • ZONIER : variable catégorielle codant la zone du bien assuré. Le code est constitué d’une lettre représentant une zone et d’un nombre représentant une partie de la zone
ZONIER nb_lignes EXPO pct_EXPO
A1 1,822.00 1,579.15 1.21%
A10 1,125.00 963.04 0.74%
A11 4,775.00 4,140.40 3.18%
A12 3,115.00 2,694.44 2.07%
A13 1,879.00 1,593.61 1.22%
A14 828.00 695.12 0.53%
A2 1,750.00 1,466.96 1.13%
A3 1,129.00 975.75 0.75%
A4 81.00 62.13 0.05%
A5 16.00 14.27 0.01%
A6 698.00 610.63 0.47%
A7 256.00 222.42 0.17%
A8 66.00 61.27 0.05%
A9 4,082.00 3,526.65 2.71%
B1 793.00 701.39 0.54%
B10 3,520.00 3,005.74 2.31%
B11 11.00 8.94 0.01%
B12 342.00 289.71 0.22%
B13 44.00 37.32 0.03%
B14 116.00 98.55 0.08%
B16 211.00 185.81 0.14%
B17 3,530.00 2,992.31 2.30%
B18 8.00 6.25 0.00%
B19 950.00 800.99 0.61%
B2 438.00 385.83 0.30%
B20 6.00 5.58 0.00%
B21 44.00 37.82 0.03%
B22 59.00 52.15 0.04%
B23 214.00 183.13 0.14%
B24 135.00 118.09 0.09%
B25 641.00 551.08 0.42%
B26 1,477.00 1,264.44 0.97%
B27 188.00 167.93 0.13%
B28 268.00 228.86 0.18%
B29 4,269.00 3,645.34 2.80%
B3 1,956.00 1,691.09 1.30%
B30 506.00 443.22 0.34%
B31 79.00 71.24 0.05%
B32 7,015.00 5,906.43 4.53%
B33 186.00 167.03 0.13%
B34 708.00 616.63 0.47%
B35 3.00 2.28 0.00%
B36 454.00 377.39 0.29%
B37 150.00 126.09 0.10%
B38 85.00 70.05 0.05%
B39 2,543.00 2,159.86 1.66%
B4 1,868.00 1,603.70 1.23%
B40 5,776.00 4,859.50 3.73%
B41 402.00 341.69 0.26%
B42 29.00 25.69 0.02%
B43 6,038.00 5,066.02 3.89%
B44 6.00 5.09 0.00%
B45 452.00 379.98 0.29%
B5 34.00 30.47 0.02%
B6 122.00 105.72 0.08%
B7 353.00 303.13 0.23%
B8 239.00 214.63 0.16%
B9 608.00 519.74 0.40%
C1 2,760.00 2,325.40 1.78%
C10 899.00 723.85 0.56%
C11 1,322.00 1,067.75 0.82%
C12 2,453.00 1,917.28 1.47%
C13 1,236.00 959.28 0.74%
C14 1,372.00 1,095.67 0.84%
C15 1,202.00 947.23 0.73%
C16 1,272.00 998.16 0.77%
C17 845.00 656.75 0.50%
C18 739.00 605.29 0.46%
C19 2,897.00 2,317.49 1.78%
C2 6,067.00 5,172.98 3.97%
C20 14,581.00 12,217.25 9.37%
C21 4,816.00 4,002.97 3.07%
C22 2,555.00 2,050.02 1.57%
C23 6,214.00 5,119.00 3.93%
C24 1,972.00 1,621.60 1.24%
C3 3,041.00 2,571.18 1.97%
C4 1,713.00 1,444.03 1.11%
C5 6,833.00 5,665.22 4.35%
C6 5,176.00 4,382.99 3.36%
C7 2,103.00 1,736.06 1.33%
C8 5,550.00 4,455.87 3.42%
C9 9,535.00 7,810.05 5.99%

  • NBSIN_TYPE1_AN1 : variable numérique indiquant le nombre de sinistre de type 1 l’année précédente
NBSIN_TYPE1_AN1 nb_lignes EXPO pct_EXPO
0 145,434.00 121,118.77 92.94%
1 9,378.00 8,465.38 6.50%
2 765.00 676.86 0.52%
3 74.00 62.11 0.05%

  • NBSIN_TYPE1_AN2 : variable numérique indiquant le nombre de sinistre de type 1 il y a 2 ans

ATTENTION : comme la table ci-dessous le démontre, cette variable présente un problème puisque toutes les lignes ont au moins un sinistre

Comme discuté dans le hackathon on ignore cette variable

NBSIN_TYPE1_AN2 nb_lignes EXPO pct_EXPO
1 146,676.00 122,175.11 93.75%
2 8,225.00 7,462.01 5.73%
3 750.00 685.99 0.53%

  • NBSIN_TYPE1_AN3 : variable numérique indiquant le nombre de sinistre de type 1 il y a 3 ans
NBSIN_TYPE1_AN3 nb_lignes EXPO pct_EXPO
0 147,569.00 122,889.56 94.30%
1 7,403.00 6,807.03 5.22%
2 625.00 576.62 0.44%
3 54.00 49.91 0.04%

  • NBSIN_TYPE2_AN1 : variable numérique indiquant le nombre de sinistre de type 2 l’année précédente
NBSIN_TYPE2_AN1 nb_lignes EXPO pct_EXPO
0 152,587.00 127,610.08 97.92%
1 2,870.00 2,540.14 1.95%
2 180.00 159.97 0.12%
3 14.00 12.93 0.01%

  • NBSIN_TYPE2_AN2 : variable numérique indiquant le nombre de sinistre de type 2 il y a 2 ans
NBSIN_TYPE2_AN2 nb_lignes EXPO pct_EXPO
0 136,330.00 114,011.30 87.48%
1 2,058.00 1,861.63 1.43%
2 113.00 103.72 0.08%
3 8.00 8.00 0.01%
NA 17,142.00 14,338.46 11.00%

  • NBSIN_TYPE2_AN3 : variable numérique indiquant le nombre de sinistre de type 2 il y a 3 ans
NBSIN_TYPE2_AN3 nb_lignes EXPO pct_EXPO
0 153,501.00 128,360.07 98.49%
1 2,019.00 1,844.33 1.42%
2 125.00 113.36 0.09%
3 6.00 5.37 0.00%

  • id : identifiant du risque, clef de jointure

  • ANNEE : variable catégorielle indiquant l’année d’observation du risque : 2016, 2017, 2018

ANNEE nb_lignes EXPO pct_EXPO
2016 54,283.00 45,171.85 34.66%
2017 52,053.00 43,654.97 33.50%
2018 49,315.00 41,496.30 31.84%

3.2 sin_train

Le fichier expo_train.csv contient la liste des contrats en risques historiquement suivis :

sin_train = read.table(file = here('data', 'raw', 'sin_train.csv'), header=T, sep=';', dec=',', encoding = 'UTF-8', stringsAsFactors = F)

datatable(head(sin_train))
str(sin_train)
## 'data.frame':    2693 obs. of  4 variables:
##  $ id   : int  15 277 643 668 730 1816 1852 2061 2270 2322 ...
##  $ NB   : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ COUT : num  521.4 3000.2 26.3 462.4 640.9 ...
##  $ ANNEE: int  2017 2016 2018 2017 2018 2018 2016 2018 2018 2017 ...
  • id : identifiant du risque, clef de jointure avec le fichier expo_train

  • NB : Nombre de sinistres de la typologie modélisée (inconnue) sur la période d’observation

NB nb_lignes
1 2,613.00
2 79.00
3 1.00

3.3 fichier combiné

On peut désormais combine les information d’exposition et de sinistres :

mrh <- expo_train %>%
      left_join(sin_train, by =c('id','ANNEE')) %>%
      replace_na(list('NB'=0, 'COUT'=0))

N’ayant pas accèsau fichier de test utilisé lors du KAckathon, on dissocie ici le fichier mrh en un fichier train (70%), un fichier val (20%) et un fichier test (10%)

set.seed(42)

trainIndex<- createDataPartition(mrh$NB>=0, p=.7, list=FALSE, time=1)

mrh_train<-mrh[trainIndex,]
mrh_test<-mrh[ -trainIndex,]

valIndex<- createDataPartition(mrh_test$NB>=0, p=.66, list=FALSE, time=1)
mrh_val<-mrh_test[ valIndex,]
mrh_test<-mrh_test[ -valIndex,]

Taux de sinistres moyen :

sum(mrh_train$NB)/sum(mrh_train$EXPO)
## [1] 0.02116882

Taux de sinistre par variable :

## `summarise()` has grouped output by 'df[[feature]]'. You can override using the `.groups` argument.
## `summarise()` has grouped output by 'df[[feature]]'. You can override using the `.groups` argument.
plot_obs<-function(dt,feature) {
  
      fig <- dt %>% plot_ly()
      fig <- fig %>% add_trace(
                     x= dt[[feature]], y= dt[['EXPO']], type = 'bar', name = 'Exposition',
                     marker = list(color = '#C9EFF9'),
                     hoverinfo = "text",
                     text = ~paste(round(EXPO,0), ' années risque')
                  )
      fig<- fig %>% add_trace(
                     x= dt[[feature]], y= dt[['Freq']], type = 'scatter', mode = 'lines', yaxis = 'y2', name= 'Fréquence',
                     hoverinfo = "text",
                     text = ~paste(round(Freq*100,2), '%')
                    )
      fig <- fig %>% layout(title = paste0('Fréquence de sinistres par ', feature),
               xaxis = list(title = ""),
               yaxis = list(side = 'left', title = 'Exposition', showgrid = FALSE, zeroline = FALSE),
               yaxis2 = list(side = 'right', overlaying = "y", title = 'Fréquence', showgrid = FALSE, zeroline = FALSE))
      
      
      return(fig)
}
plot_obs<-function(dt,feature) {
  
      fig <- dt %>% plot_ly()
      fig <- fig %>% add_trace(
                     x= dt[[feature]], y= dt[['EXPO']], type = 'bar', name = 'Exposition',
                     marker = list(color = '#C9EFF9'),
                     hoverinfo = "text",
                     text = ~paste(round(EXPO,0), ' années risque')
                  )
      fig<- fig %>% add_trace(
                     x= dt[[feature]], y= dt[['Freq']], type = 'scatter', mode = 'lines', yaxis = 'y2', name= 'Fréquence',
                     hoverinfo = "text",
                     text = ~paste(round(Freq*100,2), '%')
                    )
      fig <- fig %>% layout(title = paste0('Fréquence de sinistres par ', feature),
               xaxis = list(title = ""),
               yaxis = list(side = 'left', title = 'Exposition', showgrid = FALSE, zeroline = FALSE),
               yaxis2 = list(side = 'right', overlaying = "y", title = 'Fréquence', showgrid = FALSE, zeroline = FALSE))
      
      
      return(fig)
}
resume <- function(df, feature) {
    expo_tot <- sum(df$EXPO)

    dt <-df %>%
      group_by(df[[feature]]) %>%
      summarise(Freq = sum(NB*EXPO)/sum(EXPO), nb_lignes = n(), EXPO=sum(EXPO) ,  pct_EXPO = sum(EXPO) /  expo_tot )
    
    colnames(dt)[1] <- feature
    
    
    table<- formattable(dt,
                align=c('l','r', 'r','r', 'r'),
                list(
                    nb_lignes= accounting,
                    EXPO = accounting,
                    pct_EXPO = percent
                )
    )
  
    fig<- plot_obs(dt, feature)
    
    return(list(table=table, fig=fig))
}

3.3.1 FORMULE

FORMULE Freq nb_lignes EXPO pct_EXPO
ALL_INCLUDE 0.00572466 4,695.00 3,355.67 3.67%
CONFORT 0.02106887 61,372.00 51,858.85 56.79%
ESSENTIEL 0.02215368 15,555.00 13,597.27 14.89%
MEDIUM 0.01689978 27,334.00 22,501.75 24.64%

3.3.2 VALEUR_DES_BIENS

VALEUR_DES_BIENS Freq nb_lignes EXPO pct_EXPO
0 0.002537415 5,782.00 3,682.96 4.03%
3500 0.013571577 36,543.00 28,888.32 31.64%
9000 0.019541361 24,283.00 21,014.51 23.01%
20000 0.022504026 23,639.00 20,768.83 22.74%
35000 0.028644528 8,047.00 7,187.60 7.87%
50000 0.031410312 5,470.00 4,991.12 5.47%
80000 0.030885158 4,557.00 4,210.03 4.61%
100000 0.037175500 635.00 570.18 0.62%